/**\file
 * \brief Test cases for the BigIntegers template
 *
 * This file contains test cases to verify that the bigIntegers template
 * compiles and works as expected. These test cases could probably also be used
 * in benchmarking, but we'd better not get ahead of ourselves.
 *
 * \copyright
 * Copyright (c) 2012-2014, ef.gy Project Members
 * \copyright
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * \copyright
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * \copyright
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * \see Project Documentation: http://ef.gy/documentation/libefgy
 * \see Project Source Code: http://git.becquerel.org/jyujin/libefgy.git
 */

#include <ef.gy/test-case.h>

#include <iostream>
#include <sstream>

#include <ef.gy/big-integers.h>
#include <vector>

using namespace efgy::math;
using std::string;
using std::vector;

/**\brief Big integer bit shift tests
 * \test Test big integer bit shifts by shifting a big integer '1' a fixed
 *       number of times to the left and then comparing the result with
 *       reference data. After that the big integer is shifted to the right
 *       the same number of times and the results are again compared to the
 *       reference data.
 *
 * \param[out] log A stream for test cases to log messages to.
 *
 * \return Zero when everything went as expected, nonzero otherwise.
 */
int testBigIntegerBitShifts(std::ostream &log)
{
    Z z = Z(1);

    vector<string> reference;

    reference.push_back("2");
    reference.push_back("4");
    reference.push_back("8");
    reference.push_back("16");
    reference.push_back("32");
    reference.push_back("64");
    reference.push_back("128");
    reference.push_back("256");
    reference.push_back("512");
    reference.push_back("1024");
    reference.push_back("2048");
    reference.push_back("4096");
    reference.push_back("8192");
    reference.push_back("16384");
    reference.push_back("32768");
    reference.push_back("65536");
    reference.push_back("131072");
    reference.push_back("262144");
    reference.push_back("524288");
    reference.push_back("1048576");
    reference.push_back("2097152");
    reference.push_back("4194304");
    reference.push_back("8388608");
    reference.push_back("16777216");
    reference.push_back("33554432");
    reference.push_back("67108864");
    reference.push_back("134217728");
    reference.push_back("268435456");
    reference.push_back("536870912");
    reference.push_back("1073741824");
    reference.push_back("2147483648");
    reference.push_back("4294967296");
    reference.push_back("8589934592");
    reference.push_back("17179869184");
    reference.push_back("34359738368");
    reference.push_back("68719476736");
    reference.push_back("137438953472");
    reference.push_back("274877906944");
    reference.push_back("549755813888");
    reference.push_back("1099511627776");
    reference.push_back("2199023255552");
    reference.push_back("4398046511104");
    reference.push_back("8796093022208");
    reference.push_back("17592186044416");
    reference.push_back("35184372088832");
    reference.push_back("70368744177664");
    reference.push_back("140737488355328");
    reference.push_back("281474976710656");
    reference.push_back("562949953421312");
    reference.push_back("1125899906842624");
    reference.push_back("2251799813685248");
    reference.push_back("4503599627370496");
    reference.push_back("9007199254740992");
    reference.push_back("18014398509481984");
    reference.push_back("36028797018963968");
    reference.push_back("72057594037927936");
    reference.push_back("144115188075855872");
    reference.push_back("288230376151711744");
    reference.push_back("576460752303423488");
    reference.push_back("1152921504606846976");
    reference.push_back("2305843009213693952");
    reference.push_back("4611686018427387904");
    reference.push_back("9223372036854775808");
    reference.push_back("18446744073709551616");
    reference.push_back("36893488147419103232");
    reference.push_back("73786976294838206464");
    reference.push_back("147573952589676412928");
    reference.push_back("295147905179352825856");
    reference.push_back("590295810358705651712");
    reference.push_back("1180591620717411303424");
    reference.push_back("2361183241434822606848");
    reference.push_back("4722366482869645213696");
    reference.push_back("9444732965739290427392");
    reference.push_back("18889465931478580854784");
    reference.push_back("37778931862957161709568");
    reference.push_back("75557863725914323419136");
    reference.push_back("151115727451828646838272");
    reference.push_back("302231454903657293676544");
    reference.push_back("604462909807314587353088");
    reference.push_back("1208925819614629174706176");
    reference.push_back("2417851639229258349412352");
    reference.push_back("4835703278458516698824704");
    reference.push_back("9671406556917033397649408");
    reference.push_back("19342813113834066795298816");
    reference.push_back("38685626227668133590597632");
    reference.push_back("77371252455336267181195264");
    reference.push_back("154742504910672534362390528");
    reference.push_back("309485009821345068724781056");
    reference.push_back("618970019642690137449562112");
    reference.push_back("1237940039285380274899124224");
    reference.push_back("2475880078570760549798248448");
    reference.push_back("4951760157141521099596496896");
    reference.push_back("9903520314283042199192993792");
    reference.push_back("19807040628566084398385987584");
    reference.push_back("39614081257132168796771975168");
    reference.push_back("79228162514264337593543950336");
    reference.push_back("158456325028528675187087900672");
    reference.push_back("316912650057057350374175801344");
    reference.push_back("633825300114114700748351602688");
    reference.push_back("1267650600228229401496703205376");
    reference.push_back("2535301200456458802993406410752");
    reference.push_back("5070602400912917605986812821504");
    reference.push_back("10141204801825835211973625643008");
    reference.push_back("20282409603651670423947251286016");
    reference.push_back("40564819207303340847894502572032");
    reference.push_back("81129638414606681695789005144064");
    reference.push_back("162259276829213363391578010288128");
    reference.push_back("324518553658426726783156020576256");
    reference.push_back("649037107316853453566312041152512");
    reference.push_back("1298074214633706907132624082305024");
    reference.push_back("2596148429267413814265248164610048");
    reference.push_back("5192296858534827628530496329220096");
    reference.push_back("10384593717069655257060992658440192");
    reference.push_back("20769187434139310514121985316880384");
    reference.push_back("41538374868278621028243970633760768");
    reference.push_back("83076749736557242056487941267521536");
    reference.push_back("166153499473114484112975882535043072");
    reference.push_back("332306998946228968225951765070086144");
    reference.push_back("664613997892457936451903530140172288");
    reference.push_back("1329227995784915872903807060280344576");
    reference.push_back("2658455991569831745807614120560689152");
    reference.push_back("5316911983139663491615228241121378304");
    reference.push_back("10633823966279326983230456482242756608");
    reference.push_back("21267647932558653966460912964485513216");
    reference.push_back("42535295865117307932921825928971026432");
    reference.push_back("85070591730234615865843651857942052864");
    reference.push_back("170141183460469231731687303715884105728");
    reference.push_back("340282366920938463463374607431768211456");
    reference.push_back("680564733841876926926749214863536422912");
    reference.push_back("1361129467683753853853498429727072845824");
    reference.push_back("2722258935367507707706996859454145691648");
    reference.push_back("5444517870735015415413993718908291383296");
    reference.push_back("10889035741470030830827987437816582766592");
    reference.push_back("21778071482940061661655974875633165533184");
    reference.push_back("43556142965880123323311949751266331066368");
    reference.push_back("87112285931760246646623899502532662132736");
    reference.push_back("174224571863520493293247799005065324265472");
    reference.push_back("348449143727040986586495598010130648530944");
    reference.push_back("696898287454081973172991196020261297061888");
    reference.push_back("1393796574908163946345982392040522594123776");
    reference.push_back("2787593149816327892691964784081045188247552");
    reference.push_back("5575186299632655785383929568162090376495104");
    reference.push_back("11150372599265311570767859136324180752990208");
    reference.push_back("22300745198530623141535718272648361505980416");
    reference.push_back("44601490397061246283071436545296723011960832");
    reference.push_back("89202980794122492566142873090593446023921664");
    reference.push_back("178405961588244985132285746181186892047843328");
    reference.push_back("356811923176489970264571492362373784095686656");
    reference.push_back("713623846352979940529142984724747568191373312");
    reference.push_back("1427247692705959881058285969449495136382746624");
    reference.push_back("2854495385411919762116571938898990272765493248");
    reference.push_back("5708990770823839524233143877797980545530986496");
    reference.push_back("11417981541647679048466287755595961091061972992");
    reference.push_back("22835963083295358096932575511191922182123945984");
    reference.push_back("45671926166590716193865151022383844364247891968");
    reference.push_back("91343852333181432387730302044767688728495783936");
    reference.push_back("182687704666362864775460604089535377456991567872");
    reference.push_back("365375409332725729550921208179070754913983135744");
    reference.push_back("730750818665451459101842416358141509827966271488");
    reference.push_back("1461501637330902918203684832716283019655932542976");
    reference.push_back("2923003274661805836407369665432566039311865085952");
    reference.push_back("5846006549323611672814739330865132078623730171904");
    reference.push_back("11692013098647223345629478661730264157247460343808");
    reference.push_back("23384026197294446691258957323460528314494920687616");
    reference.push_back("46768052394588893382517914646921056628989841375232");
    reference.push_back("93536104789177786765035829293842113257979682750464");
    reference.push_back("187072209578355573530071658587684226515959365500928");
    reference.push_back("374144419156711147060143317175368453031918731001856");
    reference.push_back("748288838313422294120286634350736906063837462003712");
    reference.push_back("1496577676626844588240573268701473812127674924007424");
    reference.push_back("2993155353253689176481146537402947624255349848014848");
    reference.push_back("5986310706507378352962293074805895248510699696029696");
    reference.push_back("11972621413014756705924586149611790497021399392059392");
    reference.push_back("23945242826029513411849172299223580994042798784118784");
    reference.push_back("47890485652059026823698344598447161988085597568237568");
    reference.push_back("95780971304118053647396689196894323976171195136475136");
    reference.push_back("191561942608236107294793378393788647952342390272950272");
    reference.push_back("383123885216472214589586756787577295904684780545900544");
    reference.push_back("766247770432944429179173513575154591809369561091801088");
    reference.push_back("1532495540865888858358347027150309183618739122183602176");
    reference.push_back("3064991081731777716716694054300618367237478244367204352");
    reference.push_back("6129982163463555433433388108601236734474956488734408704");
    reference.push_back("12259964326927110866866776217202473468949912977468817408");
    reference.push_back("24519928653854221733733552434404946937899825954937634816");
    reference.push_back("49039857307708443467467104868809893875799651909875269632");
    reference.push_back("98079714615416886934934209737619787751599303819750539264");
    reference.push_back("196159429230833773869868419475239575503198607639501078528");
    reference.push_back("392318858461667547739736838950479151006397215279002157056");
    reference.push_back("784637716923335095479473677900958302012794430558004314112");
    reference.push_back("1569275433846670190958947355801916604025588861116008628224");
    reference.push_back("3138550867693340381917894711603833208051177722232017256448");
    reference.push_back("6277101735386680763835789423207666416102355444464034512896");
    reference.push_back("12554203470773361527671578846415332832204710888928069025792");
    reference.push_back("25108406941546723055343157692830665664409421777856138051584");
    reference.push_back("50216813883093446110686315385661331328818843555712276103168");
    reference.push_back("100433627766186892221372630771322662657637687111424552206336");
    reference.push_back("200867255532373784442745261542645325315275374222849104412672");
    reference.push_back("401734511064747568885490523085290650630550748445698208825344");
    reference.push_back("803469022129495137770981046170581301261101496891396417650688");
    reference.push_back("1606938044258990275541962092341162602522202993782792835301376");
    reference.push_back("3213876088517980551083924184682325205044405987565585670602752");
    reference.push_back("6427752177035961102167848369364650410088811975131171341205504");
    reference.push_back("12855504354071922204335696738729300820177623950262342682411008");
    reference.push_back("25711008708143844408671393477458601640355247900524685364822016");
    reference.push_back("51422017416287688817342786954917203280710495801049370729644032");
    reference.push_back("102844034832575377634685573909834406561420991602098741459288064");
    reference.push_back("205688069665150755269371147819668813122841983204197482918576128");
    reference.push_back("411376139330301510538742295639337626245683966408394965837152256");
    reference.push_back("822752278660603021077484591278675252491367932816789931674304512");
    reference.push_back("1645504557321206042154969182557350504982735865633579863348609024");
    reference.push_back("3291009114642412084309938365114701009965471731267159726697218048");
    reference.push_back("6582018229284824168619876730229402019930943462534319453394436096");
    reference.push_back("13164036458569648337239753460458804039861886925068638906788872192");
    reference.push_back("26328072917139296674479506920917608079723773850137277813577744384");
    reference.push_back("52656145834278593348959013841835216159447547700274555627155488768");
    reference.push_back("105312291668557186697918027683670432318895095400549111254310977536");
    reference.push_back("210624583337114373395836055367340864637790190801098222508621955072");
    reference.push_back("421249166674228746791672110734681729275580381602196445017243910144");
    reference.push_back("842498333348457493583344221469363458551160763204392890034487820288");
    reference.push_back("1684996666696914987166688442938726917102321526408785780068975640576");
    reference.push_back("3369993333393829974333376885877453834204643052817571560137951281152");
    reference.push_back("6739986666787659948666753771754907668409286105635143120275902562304");
    reference.push_back("13479973333575319897333507543509815336818572211270286240551805124608");
    reference.push_back("26959946667150639794667015087019630673637144422540572481103610249216");
    reference.push_back("53919893334301279589334030174039261347274288845081144962207220498432");
    reference.push_back("107839786668602559178668060348078522694548577690162289924414440996864");
    reference.push_back("215679573337205118357336120696157045389097155380324579848828881993728");
    reference.push_back("431359146674410236714672241392314090778194310760649159697657763987456");
    reference.push_back("862718293348820473429344482784628181556388621521298319395315527974912");
    reference.push_back("1725436586697640946858688965569256363112777243042596638790631055949824");
    reference.push_back("3450873173395281893717377931138512726225554486085193277581262111899648");
    reference.push_back("6901746346790563787434755862277025452451108972170386555162524223799296");
    reference.push_back("13803492693581127574869511724554050904902217944340773110325048447598592");
    reference.push_back("27606985387162255149739023449108101809804435888681546220650096895197184");
    reference.push_back("55213970774324510299478046898216203619608871777363092441300193790394368");
    reference.push_back("110427941548649020598956093796432407239217743554726184882600387580788736");
    reference.push_back("220855883097298041197912187592864814478435487109452369765200775161577472");
    reference.push_back("441711766194596082395824375185729628956870974218904739530401550323154944");
    reference.push_back("883423532389192164791648750371459257913741948437809479060803100646309888");
    reference.push_back("1766847064778384329583297500742918515827483896875618958121606201292619776");
    reference.push_back("3533694129556768659166595001485837031654967793751237916243212402585239552");
    reference.push_back("7067388259113537318333190002971674063309935587502475832486424805170479104");
    reference.push_back("14134776518227074636666380005943348126619871175004951664972849610340958208");
    reference.push_back("28269553036454149273332760011886696253239742350009903329945699220681916416");
    reference.push_back("56539106072908298546665520023773392506479484700019806659891398441363832832");
    reference.push_back("113078212145816597093331040047546785012958969400039613319782796882727665664");
    reference.push_back("226156424291633194186662080095093570025917938800079226639565593765455331328");
    reference.push_back("452312848583266388373324160190187140051835877600158453279131187530910662656");
    reference.push_back("904625697166532776746648320380374280103671755200316906558262375061821325312");
    reference.push_back("1809251394333065553493296640760748560207343510400633813116524750123642650624");
    reference.push_back("3618502788666131106986593281521497120414687020801267626233049500247285301248");
    reference.push_back("7237005577332262213973186563042994240829374041602535252466099000494570602496");
    reference.push_back("14474011154664524427946373126085988481658748083205070504932198000989141204992");
    reference.push_back("28948022309329048855892746252171976963317496166410141009864396001978282409984");
    reference.push_back("57896044618658097711785492504343953926634992332820282019728792003956564819968");
    reference.push_back("115792089237316195423570985008687907853269984665640564039457584007913129639936");

    for (unsigned int i = 0; i < 256; i++)
    {
        z <<= 1;
        std::ostringstream s("");
        s << z;
        if (reference[i] != s.str())
        {
            log << "big integer string conversion mismatch: #" << i << " was '" << z << "'; should have been '" << reference[i] << "'\n";
            return -1;
        }
    }

    for (int i = 255; i >= 0; i--)
    {
        std::ostringstream s("");
        s << z;
        if (reference[i] != s.str())
        {
            log << "big integer string conversion mismatch: #" << i << " was '" << z << "'; should have been '" << reference[i] << "'\n";
            return -2;
        }
        z >>= 1;
    }

    return 0;
}

TEST_BATCH(testBigIntegerBitShifts)
